home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * PLANETS.C
- *
- * (Simon Hern, 1994)
- *
- * Animation of rotating planets bouncing up and down stupidly
- *
- * Command-line options: /s to switch off end message, /t<time> to set a
- * time limit, /f<path> to specify location of data files, and /p<n> to
- * select the number of planets (1, 2 or 3, as memory allows)
- *
- * Uses XLib06 for page flipping in Mode X
- * Additional assembly language routine in GUSHCODE.ASM
- * Some extra definitions in header file PLANET.H
- *
- * Associated data files: GUSH1.DAT, GUSH2.DAT, GUSH3.DAT
- * XION1.DAT, XION2.DAT, XION3.DAT
- * (These files could've been made smaller, but that would've slowed the
- * demo down on loading as it expanded the data, so I decided against it)
- *
- *
- * As far as I can tell this program works perfectly (Ha!)
- * But obvious sources of potential problems are:
- * (i) The heavy duty maths involved with the Gush and the Xion
- * - errors here are nearly impossible to catch
- * (ii) The large arrays
- * - using arrays exactly 64k long was a bad idea
- *
- */
-
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <conio.h>
- #include <alloc.h>
- #include <string.h>
- #include <math.h>
-
- /* XLib v06 */
- #include <xlib.h>
- #include <xrect.h>
- #include <xpal.h>
- #include <xfileio.h>
- #include <xvsync.h>
-
- /* Local definitions (notably RHO: the surface resolution) */
- #include "planet.h"
-
-
-
- /* Planet drawing routine (from GUSHCODE.ASM) */
- extern void display_gush(int x, int y, int rot, char far * gu, char far * xi);
-
- /* XLib variable: start of useful video memory */
- extern WORD HiddenPageOffs;
-
-
-
- /* Screen parameters (Mode X) */
- #define SCR_WIDTH 320
- #define SCR_HEIGHT 240
-
- /* Names of additional files */
- #define GUSH_FILE "GUSH"
- #define XION_FILE "XION"
- #define FILE_EXT ".DAT"
-
- /* Default running time (secs), if set to run for a limited time */
- #define DEFAULT_TIME 120
-
- /* Maximum number of planets that can be thrown around */
- #define MAX_PLANETS 3
-
- /* Total number of colours used for planets */
- #define COLOURS 2*MAX_PLANETS
- /* Number of shades of each colour in palette */
- #define SHADES 40
-
- /* Number of background stars */
- #define STARS 200
- /* Number of palette colours used for stars */
- #define STAR_COLS 10
- /* Start position in palette of star colours */
- #define STAR_COL_START COLOURS*SHADES+1
-
-
- /* Check we've not assigned more than 256 colours */
- #if COLOURS*SHADES + STAR_COLS > 255
- #error Too many colours used in 256-colour mode
- #endif
-
-
-
- /* Structure containing data for one planet */
- typedef struct {
- char far * gush; /* Pointer to data&code for drawing the planet */
- char huge * xion; /* Pointer to planet surface data */
- int radius; /* Radius of planet (in pixels) */
- int xpos, ypos; /* Coordinates (across, down) of top-left */
- /* 'corner' of planet on screen */
- int rot; /* Degree of rotation of planet */
- int x2, y2, x3, y3; /* Remembered coordinates in previous frames */
- int dx, dr; /* Rates of change of 'xpos' and 'rot' */
- float acc; /* Constant determining 'bounce' parabola */
- int tparm, trange; /* Time parameter over parabola, and its extremes */
- int margin; /* Gap between top of screen and height of bounce */
- } PlanetStruc;
-
-
-
- /* Structure for position and colour of a star */
- typedef struct {
- unsigned int offset; /* Star position, offset into video page */
- unsigned char plane; /* Star position, ModeX video plane */
- unsigned char colour; /* Colour of star */
- } StarStruc;
-
-
-
- /* Exit functions */
- void terminate();
- int controlbreak();
-
- /* All-gone-horribly-wrong-please-let-me-out-of-here function */
- void error(char * m1, char * m2, char * m3);
-
- /* Credits and stuff */
- void end_message();
-
- /* Generate a random list of numbers */
- void shuffle(int cards[], int num);
-
- /* Load data into far memory */
- int far_load(char * fname, char far * dest, unsigned len);
-
- /* Create stars, display stars */
- void make_stars();
- void plot_stars();
-
- /* Generate palette data for planets, for stars, and for everything */
- void planet_cols();
- void star_cols();
- void set_cols();
-
- /* Do things with planets, all of them */
- void make_planets();
- void swap_planets();
- void move_planets();
- void display_planets();
- void erase_planets();
- void kill_planets();
-
- /* Do things with planets, one at a time */
- void init_planet(PlanetStruc *pp, char *gfile, char *xfile, unsigned char d);
- void kill_planet(PlanetStruc * pp);
- void move_planet(PlanetStruc * pp);
- void display_planet(PlanetStruc * pp);
- void erase_planet(PlanetStruc * pp);
-
-
-
- /* Colours to choose from when decorating the planets */
- int colours[COLOURS][3] = {
- 63, 40, 0, /* Yellow */
- 63, 0, 40, /* Pink */
- 63, 0, 5, /* Red */
- 0, 63, 0, /* Green */
- 10, 10, 63, /* Blue */
- 0, 63, 40 /* Cyan */
- };
-
-
- /* Palette of 256 colours */
- /* 0 : background (black) */
- /* 1 -- COLOURS*SHADES : colours for planets (blocks of length SHADES) */
- /* STAR_COL_START -- STAR_COL_START+STAR_COLS-1 : colours for stars */
- char far palette[256][3];
-
-
- /* Display message (or not) at end of demo */
- int message = 1;
-
- /* Directory in which to find data files */
- char fpath[80] = ""; /* Current directory by default */
-
-
- /* Array of stars */
- StarStruc stars[STARS];
-
-
- /* Array of planets */
- PlanetStruc planet[MAX_PLANETS];
-
- /* Planets listed in the order they appear on screen */
- int order[MAX_PLANETS];
-
- /* The number of planets actually used */
- int planets;
-
-
-
- /* CODE STARTS HERE ! */
-
- int main(int argc, char *argv[]) {
-
- int timer=0, twait, time_up=0;
- time_t tstart=time(NULL);
- int s;
-
- randomize();
-
- /* As many planets as will fit in memory */
- planets = farcoreleft() / (65535L + 4*(long)RHO*RHO);
- if ( planets > MAX_PLANETS ) planets = MAX_PLANETS;
- if ( planets <= 0 ) {
- error("It might help if there was a little free memory", "", "");
- }
-
- /* Command-line options */
- for ( s = 1 ; s < argc ; s++ ) {
- if ( argv[s][0] != '/' && argv[s][0] != '-' ) {
- error(argv[s], "? That\'s no way to select a program option!", "");
- }
- if ( argv[s][1] == 's' || argv[s][1] == 'S' ) {
- /* Switch off end message */
- message = 0;
- } else if ( argv[s][1] == 't' || argv[s][1] == 'T' ) {
- /* Run demo for fixed length of time */
- timer = 1;
- twait = atoi(argv[s]+2);
- if ( twait <= 0 ) twait = DEFAULT_TIME;
- } else if ( argv[s][1] == 'f' || argv[s][1] == 'F' ) {
- /* Set file search path */
- strcpy(fpath, argv[s]+2);
- if ( fpath[0] != '\0' && fpath[strlen(fpath)-1] != '\\'
- && fpath[strlen(fpath)-1] != ':' ) {
- fpath[strlen(fpath)+1] = '\0';
- fpath[strlen(fpath)] = '\\';
- }
- } else if ( argv[s][1] == 'p' || argv[s][1] == 'P' ) {
- /* Select number of planets to bounce */
- planets = argv[s][2] - '0';
- if ( planets<1 || planets>MAX_PLANETS || strlen(argv[s])>3 ) {
- error("How many planets?!", "", "");
- }
- } else error("What\'s ", argv[s], " supposed to mean then?");
- }
-
- /* Load and arrange data */
- make_planets();
- make_stars();
-
- /* XLib vsynced trip(p)le buffering (good stuff!) */
- /* Screen updates 30 times a second (sets a maximum animation rate) */
- x_set_mode(X_MODE_320x240, SCR_WIDTH);
- x_install_vsync_handler(2);
- x_set_tripplebuffer(SCR_HEIGHT);
- /* Last one out, please turn off Mode X */
- atexit(terminate);
- ctrlbrk(controlbreak);
-
- /* Palette */
- set_cols();
-
- /* Now, until a key is pressed or time runs out... */
- while ( !kbhit() && !time_up ) {
-
- move_planets(); /* Reposition planets for next frame */
- plot_stars(); /* Redraw the background stars */
- display_planets(); /* Draw the planets */
- x_page_flip(0,0); /* Display this frame */
- erase_planets(); /* Clean the planet remains from the old frame */
- swap_planets(); /* Change the order of the planets occasionally */
-
- if ( time(NULL) > tstart + twait ) time_up = 1;
- }
-
- /* Tidy up and go home */
- while ( kbhit() ) getch();
- kill_planets();
- if ( timer && !time_up ) return 1;
- return 0;
- }
-
-
-
- /* Exit function (shut off graphics mode before terminating) */
-
- void terminate() {
- x_remove_vsync_handler();
- x_text_mode();
- if ( message ) end_message();
- }
-
-
-
- /* Control-Break handler */
-
- int controlbreak() {
- terminate();
- return 0;
- }
-
-
-
- /* Display error message (in up to three bits), then die */
-
- void error(char * m1, char * m2, char * m3) {
- end_message();
- printf("\nSimon says: %s%s%s\n\n", m1, m2, m3);
- exit(-1);
- }
-
-
-
- /* Display the end message */
-
- void end_message() {
- printf("\n"
- " BOUNCING PLANETS DEMO\n"
- " Simon Hern (22 Harrington Drive, Bedford, MK41 8DB, England)\n"
- " April 1994\n"
- "\n"
- " Command-line options:\n"
- " /s : suppress this end message\n"
- " /t<time> : stop demo after <time> seconds\n"
- " /p<n> : bounce <n> planets (up to 3)\n"
- " /f<path> : look for data files in <path> directory\n"
- "\n");
- }
-
-
-
- /* Places numbers 0 to ('num'-1) into 'cards' array in a random order */
- /* Used for deciding which planet uses which data */
-
- void shuffle(int cards[], int num) {
- int i, r;
- for ( i=0 ; i<num ; i++ ) cards[i] = -1;
- for ( i=0 ; i<num ; i++ ) {
- do { r = random(num); }
- while ( cards[r] != -1 );
- cards[r] = i;
- }
- }
-
-
-
- /* Function to load data to 'far' array (up to 65535 bytes) */
- /* Uses XLib file functions (since they work with 'far') */
-
- int far_load(char * fname, char far * dest, unsigned len) {
- int fin;
- unsigned l;
-
- fin = f_open(fname, F_RDONLY);
- if ( fin == FILE_ERR ) return 0;
-
- l = f_readfar(fin, dest, len);
-
- f_close(fin);
- return l;
- }
-
-
-
- /* Fill up the array of stars; random positions, random colours */
-
- void make_stars() {
- int s;
- for ( s=0 ; s<STARS ; s++ ) {
- stars[s].offset = random(SCR_WIDTH*(SCR_HEIGHT/4));
- stars[s].plane = 1 << random(4);
- stars[s].colour = STAR_COL_START + random(STAR_COLS);
- }
- }
-
-
-
- /* Plot all the stars onto the 'hidden' video page */
-
- void plot_stars() {
- int s;
- for ( s=0 ; s<STARS ; s++ ) {
- outport(0x03c4, (256*(int)stars[s].plane)+2);
- pokeb(0xa000, HiddenPageOffs + stars[s].offset, stars[s].colour);
- }
- }
-
-
-
- /* Choose random colours for the planets and fill the palette */
-
- void planet_cols() {
- int i,j;
- float s;
- int cards[COLOURS];
-
- shuffle(cards, COLOURS);
- for ( i = 0 ; i < SHADES ; i++ ) {
- s = i/((float)SHADES-1);
-
- for ( j = 0 ; j < COLOURS ; j += 2 ) {
- palette[i + j*SHADES + 1][0] = (1-s) * colours[cards[j]][0];
- palette[i + j*SHADES + 1][1] = (1-s) * colours[cards[j]][1];
- palette[i + j*SHADES + 1][2] = (1-s) * colours[cards[j]][2];
-
- palette[i + (j+1)*SHADES + 1][0] = s * colours[cards[j+1]][0];
- palette[i + (j+1)*SHADES + 1][1] = s * colours[cards[j+1]][1];
- palette[i + (j+1)*SHADES + 1][2] = s * colours[cards[j+1]][2];
- }
- }
- }
-
-
-
- /* Set up the star colours in the palette (shades of grey) */
-
- void star_cols() {
- int c;
- for ( c = 0 ; c < STAR_COLS ; c++ ) {
- palette[STAR_COL_START + c][0] = palette[STAR_COL_START + c][1]
- = palette[STAR_COL_START + c][2] = 63.0 * (c+1) / (float)STAR_COLS;
- }
- }
-
-
-
- /* Generate palette data for background, planets and stars */
-
- void set_cols() {
- palette[0][0] = palette[0][1] = palette[0][2] = 0;
- planet_cols();
- star_cols();
- x_put_pal_raw((char far *)palette, 256, 0);
- }
-
-
-
- /* Initialise all the planets (includes loading in data) */
-
- void make_planets() {
- int i;
- int gcards[MAX_PLANETS];
- int xcards[MAX_PLANETS];
- char gfile[80];
- char xfile[80];
-
- /* Jack Names the Planets */
- shuffle(gcards, MAX_PLANETS);
- shuffle(xcards, MAX_PLANETS);
- /* Load in data for the active planets in a random order */
- for ( i = 0 ; i < planets ; i++ ) {
- strcpy(gfile, fpath);
- strcpy(xfile, fpath);
- strcat(gfile, GUSH_FILE);
- strcat(xfile, XION_FILE);
- gfile[strlen(gfile)+1] ='\0';
- gfile[strlen(gfile)] ='1' + gcards[i];
- xfile[strlen(xfile)+1] ='\0';
- xfile[strlen(xfile)] ='1' + xcards[i];
- strcat(gfile, FILE_EXT);
- strcat(xfile, FILE_EXT);
- /* Files are: GUSH1.DAT, XION1.DAT, GUSH2.DAT, XION2.DAT, etc */
- init_planet(&planet[i], gfile, xfile, i*2*SHADES);
- }
-
- /* Random starting x coordinate */
- for ( i = 0 ; i < planets ; i++ ) {
- planet[i].xpos = random(SCR_WIDTH - 2*planet[i].radius);
- }
-
-
- /* Some constants, different for each planet (3 planets accounted for) */
- planet[0].dx = 3;
- planet[0].dr = -2;
- planet[0].acc = 0.2;
- planet[0].margin = 0;
-
- planet[1].dx = -2;
- planet[1].dr = -3;
- planet[1].acc = 0.35;
- planet[1].margin = 10;
-
- planet[2].dx = -3;
- planet[2].dr = 4;
- planet[2].acc = 0.3;
- planet[2].margin = 25;
-
- /* Parameter range and random starting time */
- for ( i = 0 ; i < planets ; i++ ) {
- planet[i].trange = sqrt(
- (SCR_HEIGHT - planet[i].margin - 2*planet[i].radius - 1)
- / planet[i].acc );
- planet[i].tparm = planet[i].trange * (random(199)-99) / 100.0;
- }
-
- /* The planets in order */
- for ( i = 0 ; i < planets ; i++ ) order[i] = i;
- }
-
-
-
- /* From time to time, switch over the orderings of two planets */
- /* Planets must not be overlapping at the time */
-
- void swap_planets() {
- static int swap = 50;
- int x, s;
-
- if ( planets <= 1 ) return;
-
- if ( --swap == 0 ) {
- swap= 10 + random(40);
- x = random(planets-1);
- if ( ( planet[order[x]].xpos - planet[order[x+1]].xpos
- > 2*planet[order[x+1]].radius )
- || ( planet[order[x+1]].xpos - planet[order[x]].xpos
- > 2*planet[order[x]].radius ) ) {
- s = order[x];
- order[x] = order[x+1];
- order[x+1] = s;
- }
- }
- }
-
-
-
- /* Move all of the planets */
-
- void move_planets() {
- int x;
- for ( x = 0 ; x < planets ; x++ ) move_planet(&planet[order[x]]);
- }
-
-
-
- /* Display all of the planets */
-
- void display_planets() {
- int x;
- for ( x = 0 ; x < planets ; x++ ) display_planet(&planet[order[x]]);
- }
-
-
-
- /* Erase all of the planets */
-
- void erase_planets() {
- int x;
- for ( x = 0 ; x < planets ; x++ ) erase_planet(&planet[order[x]]);
- }
-
-
-
- /* Kill all of the planets */
-
- void kill_planets() {
- int x;
- for ( x = 0 ; x < planets ; x++ ) kill_planet(&planet[order[x]]);
- }
-
-
-
- /* Initialise a planet, given a gush file name and a xion file name */
- /* Add 'd' to every point in xion (different colours for different planets) */
-
- void init_planet(PlanetStruc *pp, char *gfile, char *xfile, unsigned char d) {
- int x,y;
- char far * dest;
- char far * source;
-
- /* Allocate memory */
- pp->gush = (char far *)farmalloc(65535L);
- if ( pp->gush == NULL ) {
- error("Too much *gush*, too little memory", "", "");
- }
- pp->xion = (char huge *)farmalloc(4*(long)RHO*RHO);
- if ( pp->xion == NULL ) {
- error("Too much *xion*, too little memory", "", "");
- }
-
- /* Load files */
- if ( ! far_load(gfile, pp->gush, 65535) ) {
- error("What have you done with my ", gfile, " file?");
- }
- if ( ! far_load(xfile, (char far *)pp->xion, 2*RHO*RHO) ) {
- error("What have you done with my ", xfile, " file?");
- }
-
- /* Expand Complexion */
- /* (Each line repeated, 'd' added on at each point) */
- source = ((char far *)(pp->xion)) + 2*RHO*RHO - 1;
- dest = ((char far *)(pp->xion)) + 4*RHO*RHO - 1;
- for ( y = RHO ; y > 0 ; y-- ) {
- for ( x = 2*RHO ; x > 0 ; x-- ) {
- *dest = *(dest-2*RHO) = *source + d;
- source--;
- dest--;
- }
- dest -= 2*RHO;
- }
-
- /* Initialise a variable */
- pp->radius = pp->gush[0];
-
- /* Blank some other variables */
- pp->xpos = pp->ypos = pp->x2 = pp->y2 = pp->x3 = pp->y3 = 0;
- pp->rot = pp->dr = pp->dx = pp->tparm = pp->margin = 0;
- pp->trange = 10;
- pp->acc = 1;
- }
-
-
-
- /* Deallocate planet's memory */
-
- void kill_planet(PlanetStruc * pp) {
- farfree((void far *)pp->gush);
- farfree((void far *)pp->xion);
- }
-
-
-
- /* Move planet: constant x velocity (with bounce at ends), */
- /* parabola in y (based on tparm), constant rotational velocity */
-
- void move_planet(PlanetStruc * pp) {
-
- pp->x3 = pp->x2;
- pp->y3 = pp->y2;
- pp->x2 = pp->xpos;
- pp->y2 = pp->ypos;
-
- pp->xpos += pp->dx;
- if ( (pp->xpos) >= SCR_WIDTH - 2*(pp->radius) ) {
- pp->xpos = SCR_WIDTH - 2*(pp->radius) - 1;
- pp->dx = -(pp->dx);
- }
- if ( (pp->xpos) < 0 ) {
- pp->xpos = 0;
- pp->dx = -(pp->dx);
- }
-
- pp->ypos = pp->margin + (pp->acc) * (pp->tparm) * (pp->tparm);
- if ( ++(pp->tparm) > (pp->trange) ) {
- pp->tparm = -(pp->tparm) + 1;
- }
-
- pp->rot += pp->dr;
- while ( pp->rot < 0 ) pp->rot += 2*RHO;
- while ( pp->rot >= 2*RHO ) pp->rot -= 2*RHO;
- }
-
-
-
- /* Draw the planet (checking position is within bounds) */
-
- void display_planet(PlanetStruc * pp) {
- if ( pp->xpos < 0 || pp->xpos >= SCR_WIDTH-2*(pp->radius) ) pp->xpos = 0;
- if ( pp->ypos < 0 || pp->ypos >= SCR_HEIGHT-2*(pp->radius) ) pp->ypos = 0;
- if ( pp->rot < 0 || pp->rot >= 2*RHO ) pp->rot = 0;
-
- display_gush(pp->xpos, pp->ypos, pp->rot,
- (char far *)pp->gush, (char far *)pp->xion);
- }
-
-
-
- /* Draw black rectangle over old planet position */
-
- void erase_planet(PlanetStruc * pp) {
- x_rect_fill(pp->x3, pp->y3,
- (pp->x3) + 2*(pp->radius), (pp->y3) + 2*(pp->radius),
- HiddenPageOffs, 0);
- }
-
-
-